package com.cryptoneedle.center.source.service.enhance;


import com.bubbles.engine.data.core.repository.BaseRepository;
import com.bubbles.engine.data.core.service.BaseService;
import com.cryptoneedle.center.source.entity.enhance.Dimension;
import com.cryptoneedle.center.source.entity.metadata.Catalog;
import com.cryptoneedle.center.source.entity.metadata.Database;
import com.cryptoneedle.center.source.enums.DimensionOriginType;
import com.cryptoneedle.center.source.key.enhance.DimensionKey;
import com.cryptoneedle.center.source.repository.enhance.DimensionRepository;
import com.cryptoneedle.center.source.service.crud.*;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>description: 源数据源-增强-维度 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-20
 */
@Slf4j
@Service
public class DimensionService extends BaseService<Dimension, DimensionKey> {

    @Resource
    private DimensionService dimensionService;
    @Resource
    private DimensionRepository dimensionRepository;

    @Override
    public BaseRepository<Dimension, DimensionKey> getRepository() {
        return this.dimensionRepository;
    }

    @Autowired
    private FoundDataService select;
    @Autowired
    private AddDataService add;
    @Autowired
    private PatchDataService patch;
    @Autowired
    private SaveDataService save;
    @Autowired
    private DeleteDataService delete;

    @Transactional
    public void syncDatabase(Catalog catalog, Database database) {
        // 根据主键约束提取
        List<Dimension> primaryConstraintDimension = select.constraintPrimaries(database)
                .stream()
                .map(primary -> new Dimension()
                        .setCatalogName(primary.getCatalogName())
                        .setDatabaseName(primary.getDatabaseName())
                        .setTableName(primary.getTableName())
                        .setDimensionName(primary.getConstraintName())
                        .setColumnName(primary.getColumnName())
                        .setPosition(primary.getPosition())
                        .setOrigin(DimensionOriginType.PRIMARY_CONSTRAINT)
                        .setEnabled(false))
                .toList();
        // 根据唯一键约束提取
        List<Dimension> uniqueConstraintDimension = select.constraintUniques(database)
                .stream()
                .map(unique -> new Dimension()
                        .setCatalogName(unique.getCatalogName())
                        .setDatabaseName(unique.getDatabaseName())
                        .setTableName(unique.getTableName())
                        .setDimensionName(unique.getConstraintName())
                        .setColumnName(unique.getColumnName())
                        .setPosition(unique.getPosition())
                        .setOrigin(DimensionOriginType.UNIQUE_CONSTRAINT)
                        .setEnabled(false))
                .toList();
        // 根据唯一索引提取
        List<Dimension> uniqueIndexDimension = select.indexUniques(database)
                .stream()
                .map(unique -> new Dimension()
                        .setCatalogName(unique.getCatalogName())
                        .setDatabaseName(unique.getDatabaseName())
                        .setTableName(unique.getTableName())
                        .setDimensionName(unique.getIndexName())
                        .setColumnName(unique.getColumnName())
                        .setPosition(unique.getPosition())
                        .setOrigin(DimensionOriginType.UNIQUE_INDEX)
                        .setEnabled(false))
                .toList();

        List<Dimension> dimensions = new ArrayList<>(primaryConstraintDimension.size() + uniqueConstraintDimension.size() + uniqueIndexDimension.size());
        dimensions.addAll(primaryConstraintDimension);
        dimensions.addAll(uniqueConstraintDimension);
        dimensions.addAll(uniqueIndexDimension);

        dimensionService.compareData(database, dimensions);
    }

    @Transactional
    public void compareData(Database database, List<Dimension> dealList) {
        List<Dimension> originList = select.dimensions(database);
        // 已存在
        Map<String, Dimension> originMap = Maps.uniqueIndex(originList, origin -> origin.dimensionKey().toString());
        // 待处理
        Map<String, Dimension> dealMap = Maps.uniqueIndex(dealList, deal -> deal.dimensionKey().toString());

        // 新增
        List<Dimension> extraList = dealList.stream().filter(deal -> !originMap.containsKey(deal.dimensionKey().toString())).toList();

        // 保存
        List<Dimension> existsList = originList
                .stream()
                .filter(origin -> dealMap.containsKey(origin.dimensionKey().toString()))
                .peek(origin -> {
                    Dimension deal = dealMap.get(origin.dimensionKey().toString());
                    origin.setPosition(deal.getPosition());
                    origin.setEnabled(deal.getEnabled());
                }).toList();

        // 移除
        List<Dimension> missList = originList.stream()
                //　防止移除手动添加的维度
                .filter(item -> !DimensionOriginType.MANUAL.equals(item.getOrigin()))
                .filter(item -> !dealMap.containsKey(item.dimensionKey().toString()))
                .toList();

        add.dimensions(extraList);
        save.dimensions(existsList);
        delete.dimensions(missList);

        log.info("[SYNC] {} -> {} -> 维度同步   -> Dimension          => 共计{} | 新增{} | 删除{}", database.getCatalogName(), database.getDatabaseName(), String.format("%5d", dealList.size()), String.format("%5d", extraList.size()), String.format("%5d", missList.size()) + (
                !missList.isEmpty() ? " => " + missList
                        .stream()
                        .map(dimension -> dimension.getTableName() + " - " + dimension.getDimensionName() + " - " + dimension.getColumnName())
                        .collect(Collectors.joining(",")) : ""));
    }
}